package net.ifilm.service;

import net.ifilm.common.Constants;
import net.ifilm.common.SpiderCache;
import net.ifilm.common.SpiderException;
import net.ifilm.db.DBExecutor;
import net.ifilm.domain.Configuration;
import net.ifilm.domain.Message;
import net.ifilm.util.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.File;
import java.io.IOException;
import java.util.*;

public class XddyWebSiteService implements IWebSiteService {

    private static final Log log = LogFactory.getLog(XddyWebSiteService.class);

    private DBExecutor dbExecutor = null;

    private Configuration configuration = null;

    private Map<String, List<String>> webPageMap = null;

    private List<String> filmPageList = null;

    // =================================================================================================================

    public XddyWebSiteService(Configuration configuration) throws Exception {
        this.configuration = configuration;
        this.dbExecutor = new DBExecutor();
        this.webPageMap = new HashMap<String, List<String>>();
        this.filmPageList = new ArrayList<String>();

        validateDownloadPath(configuration.getDownloadPath());
        prepareWebPage(configuration.getSitelist());
    }

    private void validateDownloadPath(String downloadPath) {
        File downloadDir = new File(downloadPath);
        if (!downloadDir.exists()) throw new RuntimeException("download path " + downloadPath + " is not exist");
        if (!downloadDir.isDirectory()) throw new RuntimeException("download path " + downloadDir + " is not directory");
        if (!downloadDir.canWrite()) throw new RuntimeException("download path " + downloadDir + " cann't wirte");

        if (log.isInfoEnabled()) {
            log.info("validate download path " + downloadDir + " is usefully");
        }
    }

    private void prepareWebPage(String siteList) throws Exception {
        separatePageList(siteList);
        log.info("film separate web page process complate");

        /*
         * 从缓存webPageMap中获取value并遍历每个页面电影连接放入缓存List中
         */
        Document doc = null;
        String key = null;
        List<String> valueList = null;
        for (Map.Entry<String, List<String>> entry : webPageMap.entrySet()) {
            key = entry.getKey();
            valueList = entry.getValue();

            if (log.isInfoEnabled()) { log.info("process web page fragments " + key); }

            for (String page : valueList) {
                if (log.isDebugEnabled()) { log.debug("Parse > " + page); }

                doc = createDocument(page);
                cacheSingleFilmLink(doc);
            }
        }
        log.info("single film page link is process complate, page list size is " + filmPageList.size());
    }

    private void separatePageList(String pageList) throws IOException {
        if (pageList.indexOf(Constants.SEPARATE) == -1) {
            calcutePages(pageList);
        } else {
            String[] filmPageList = pageList.split(Constants.SEPARATE);
            for (String page : filmPageList) {
                calcutePages(page);
            }
        }
    }

    private void calcutePages(String page) throws IOException {
        List<String> webPageList = new ArrayList<String>();
        int endIndex = getEndIndex(page);
        if (log.isDebugEnabled()) {
            log.debug(page + " -> " + endIndex);
        }

        StringBuffer webPage = new StringBuffer();
        webPage.append(page).append("index.html");
        webPageList.add(webPage.toString());
        webPage.setLength(0);

        for (int startIndex = 2; startIndex <= endIndex; startIndex++) {
            webPage.append(page).append("index").append(startIndex).append(".html");
            webPageList.add(webPage.toString());

            log.debug(webPage.toString());
            webPage.setLength(0);
        }

        webPageMap.put(page, webPageList);
    }

    private int getEndIndex(String webPage) throws IOException {
        Connection conn = Jsoup.connect(webPage);
        conn.timeout(Constants.CONNECT_TIMEOUT);
        Document doc = conn.get();
        String str = doc.select(".pagegbk").last().attr("href");
        int endIndex = Integer.parseInt(StringUtil.extraKeyword(".*index(.*)\\.html", str));
        return endIndex;
    }

    @Override
    public void process() throws Exception {
        Message message = null;
        for (String filmPageLink : filmPageList) {
            message = new Message();
            message.setDbExecutor(dbExecutor);
            message.setDownloadPath(configuration.getDownloadPath());
            message.setDomain(configuration.getSiteDomain());
            message.setFilmLinkPage(filmPageLink);

            Constants.messageQueue.put(message);
        }
    }

    private void cacheSingleFilmLink(Document doc) throws SpiderException {
        Elements elements = doc.select(".listcont li");
        SpiderCache spiderCache = SpiderCache.getInstance();

        String filmName = null;
        String filmUri = null;
        StringBuffer singleFilmPage = new StringBuffer();
        for (Element liElement : elements) {
            filmName = liElement.select("dl dd.bt h2 a").text();

            if (spiderCache.getFilmNameMapValue(filmName) != null) {
                if (log.isDebugEnabled()) {
                    log.debug("[" + filmName + "] already exist, ignore and go on.");
                }

                continue;
            }

            filmUri = liElement.select("dl").last().select("a").attr("href");
            singleFilmPage.append(configuration.getSiteDomain()).append(filmUri);
            filmPageList.add(singleFilmPage.toString());
            singleFilmPage.setLength(0);
        }
    }

    private Document createDocument(String pageUrl) throws IOException {
        Connection conn = Jsoup.connect(pageUrl);
        conn.timeout(Constants.CONNECT_TIMEOUT);
        Document doc = conn.get();
        return doc;
    }

}
